home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-18 | 29.8 KB | 1,077 lines |
- (c) Copyright 1990 Commodore-Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice,
- and is provided "as is" without warranty of any kind, either express
- or implied. The entire risk as to the use of this information is
- assumed by the user.
-
-
- Creating Your Own Library
-
-
- Michael Sinz
-
- On the Amiga, programmers can easily add their own function
- libraries to the system. The LIBS: directory of the Workbench
- disk contains .library files. These are disk-loadable function
- libraries that are linked into the system only when needed by an
- application. For instance, the IEEE math functions comprise a
- disk-loadable library.
-
- Disk-loadable libraries are sometimes called shared-code
- libraries since their functions are callable from multiple
- programs at once. This means that all functions in the library
- must be reentrant. Also, any functions that the library calls
- have to be reentrant too. For instance, sprintf() from the
- standard C link library is not reentrant. and should not be
- called from a disk-loadable library. In addition to being
- reentrant, the library has to correctly employ semaphores to
- protect any shared data structures.
-
- This article presents a working example of a disk-loadable
- library and shows you how to create your own using Lattice C.
- You may also want to refer to the assembly-language example
- library in the Includes and Autodocs Manual (Addison-Wesley, ISBN
- 0-201-18177-0, page G-13). For the basics on how libraries work
- on the Amiga, refer to the ROM Kernel Manual: Libraries and
- Devices (Addison-Wesley, ISBN 0-201-18187-8, page 229).
-
- Selecting Your Library Functions
-
- The first step in creating your own library is to select the
- functions you will use for entry points and come up with the
- parameters the functions will need. The parameters must be data
- items that can fit into a processor register. That is, you can
- not pass a structure, but you can pass a pointer to it. Our
- example library will consist of exactly three functions, Cube(),
- Count(), and FunStuff(). The parameters to the three routines
- are:
-
- long = Cube (long num);
- d0 d0
-
- long = Count (void);
- d0
-
- void FunStuff(long num,char *text);
- d0 a0
-
-
- Selecting Registers for Each Function Argument
-
- In this example, the Cube() function has one argument, the
- Count() function has none, and the FunStuff() function has two.
- Here are the rules for selecting registers to use for the
- function arguments:
-
- o Don't select registers arbitrarily. A thoughtful selection
- makes a real difference in the performance of your library.
- o Select registers starting at the low numbers. (d0, d1, d2...)
- o Select registers that best describe what the argument is. If
- the argument is a data item select a d register. If the
- argument is an address, select an a register.
- o You must not select a4, a6 or a7 since these are special cases.
- If you do the system will crash.
-
-
- Make Your Function Prototypes File
-
- For this example, the prototypes would be:
- long __saveds __asm LIBCube(register __d0 long num);
- long __saveds __asm LIBCount(void);
- void __saveds __asm LIBFunStuff(register __d0 long num,
- register __a0 char *text);
-
- Note the compiler directives __saveds, __asm and register __d0.
- The __saveds directive is used to define a subroutine that loads
- up the global base pointer into a4 upon entry. That way the
- small-data model can be used for compilation. The __asm
- directive is used to define a subroutine which takes its
- parameters in a specific register. The register __d0 directive
- actually tells which register to use for the parameter.
-
-
- From the Prototypes, Make a .fd File
-
- The .fd file is used to make #pragma statements for the compiler
- such that programs can call your library. It also is used by the
- linker (BLink) to make the library table. For this example the
- .fd file would be:
-
- ##base _ExampleLibBase
- ##bias 30
- Cube(num)(A0)
- Count()
- FunStuff(num,text)(D0/A0)
- ##end
-
- The first line describes the library base name. The second line
- is the standard table bias needed for a library. The next three
- lines give the function call names and the registers they use (if
- any).
-
-
- Set Up the Custom Init and Expunge Code For Your Library
-
- The Init code should initialize anything special that may be
- needed by the library. This could include opening other
- libraries that your library might be calling or initializing data
- structures it may need. In this example, there is a global
- semaphore that is initialized during the Init routine and a few
- other libraries that are opened.
-
- Expunge frees anything allocated by the Init code. Our example
- library closes the libraries that it uses. Refer to the file
- Examplelib_Custom.c to see how this is done.
-
- Note that these are custom routines specific to the library.
- These are called by the generic initialize and expunge entries
- which are part of every library. The generic initialization,
- open, close, and expunge routines are listed in the libinit.c
- file.
-
-
- Write Your Library Functions
-
- Of course our library functions will need some code to execute.
- The code for this example is listed in the file Examplelib.c.
-
-
- Put Revision Information Into Header Files
-
- The library revision number is important for keeping track of
- versions and helps insure future compatibility for the library.
- For this example, the revision information appears in the header
- files Examplelib_rev.h and Examplelib_rev.i.
-
-
- Compile the Library
-
- Once you have all the required files for a library, compile it.
- Then copy the resulting library file to the LIBS: directory.
- (Note that you can put the library anywhere you want so long as
- you give the complete path name to the library in the
- OpenLibrary() call.)
-
- The lmk file for our example library is listed below. Keep in
- mind that BLink uses the name of the binary file that you
- compile as the name of the library. For this example, the name
- is Examplelib.library.
-
- Test the Library
-
- You should test and debug the library as a normal C linked
- library before compiling it into the final disk-loadable form.
- Once the functions are debugged, create the .library version and
- do the final testing. A test program for the example library
- called libtest.c is listed below.
-
- When you are making changes to the disk-loadable version of a
- library, you will need to cause a system expunge in order to
- flush the old version of the library from the system so that the
- new one can be tried. To do this you would first make sure all
- programs have closed the old library, place the new version of
- the library in the LIBS: directory, and finally, cause a system
- expunge. This can be done with the avail -flush command from the
- CLI or with the Workbench debug-menu option, flushlibs. Note
- that you must use loadwb -debug in you startup script to get the
- Workbench debug-menu.
-
- The Example Library Files
-
- Altogether there are 13 files in this example library.
-
- 1) examplelib.c
- This is the place where the library function call code is. This
- can be more than one module, but for this example is just one.
-
- 2) examplelib.h
- Header file for ExampleLib.c that is shared with
- examplelib_custom.c in defining any and all global data. Note
- that global data that is modified needs to be protected via
- semaphores.
-
- 3) examplelib_custom.c
- This is the custom library initialization and expunge code. The
- routines in here are used to set up library-specific items upon
- loading of the library and to clean up when an expunge occurs.
- The routines here are called by the standard library
- initialization and expunge entries of the library
- in the libinit.c file.
-
- 4) examplelib_custom.h
- This is the prototype header for the examplelib_custom.c
- initialization and expunge code.
-
- 5) examplelib_lib.fd
- This is the .fd file (function definition) for the library. It
- defines the function names, their position in the library vector
- table, and the registers that their parameters are passed in. It
- also is used to generate the #pragmas in the examplelib_pragma.h
- file and to tell the linker how
- to build the library itself.
-
-
- 6) examplelib_proto.h
- These are ANSI style prototypes for the library functions.
-
- 7) examplelib_rev.h
- This header file contains the C-language definitions of the
- library version.
-
- 8) examplelib_rev.i
- This is the assembly-language definitions of the library version.
-
- 9) libent.a
- This is the Resident structure (sometimes referred to as a
- RomTag) which is required to be in the first hunk of libraries or
- other system-objects. It identifies the object and tells the
- system how to initialize it (i.e. the address of the
- initialization code). For more on the Resident structure, refer
- to the ROM Kernel Manual: Libraries and Devices, page 234, or see
- the exec/resident.h and .i files in the Includes and Autodocs
- Manual.
-
- 10) endtag.a
- This is just a label that is linked into the end of the file so
- that the RomTag can point to the end of the RomTag hunk.
-
- 11) libinit.c
- These are the library initialization, expunge, open, and close
- routines required in all libraries. In general, this file will
- remain the same regardless of changes you might make to the
- library. The initialization and expunge routines here will call
- the custom library initialization routines in the
- examplelib_custom.c file. Any special setup you might need would
- be done in that file.
-
- 12) libtest.c
- Example code to call the library routines. This just tests the
- library calls and shows that they work.
-
- 13) lmkfile
- This is the makefile rules for the Lattice LMK program. This
- will produce all of the files needed. To run the lmkfile and
- compile the library, type lmk at the CLI. You must be in the
- directory containing all the library files when you give the
- command.
-
-
-
-
- Important Compilation Notes
-
- To make this library compile correctly you will need to modify
- one of the files that came with Lattice C. The file
- INCLUDE:proto/exec.h needs to have the #pragma syscall changed to
- #pragma libcall SysBase. This needs to be done to all of the
- #pragmas in the exec.h file.
-
- For example, you would change:
-
- #pragma syscall AllocMem c6 1002
-
- to this:
-
- #pragma libcall SysBase AllocMem c6 1002
-
- This change tells the compiler to load ExecBase not from
- AbsExecBase but from the local SysBase which was initialized at
- the start of the code. This change is required in order to make
- the -ml (make library) option of Lattice work correctly. It also
- reduces the amount of access to MEMF_CHIP type of memory since
- AbsExecBase (location 4) will no longer be referenced. This can
- make for a speed improvement if SysBase is in MEMF_FAST memory
- and you are doing complex graphics with lots of video-DMA; the
- processor won't be competing with the graphics chips for access
- to chip RAM.
-
- Since we are using SysBase instead of AbsExecBase, the following
- line must be added to the
- INCLUDE:proto/exec.h file:
-
- extern struct ExecBase *SysBase;
-
- Anywhere near the start of the file is fine. A complete listing
- of all 13 modules in the example library is given on the
- following pages.
-
-
-
-
- /*
- * 1) examplelib.c - example shared library to be made by blink 5.04
- *
- * These are the actual library functions...
- */
-
- #include <exec/types.h>
- #include <exec/libraries.h>
- #include <intuition/intuition.h>
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <proto/graphics.h>
-
- #include <dos.h>
-
- /*
- * This is the file that contains the few global data value
- * definitions...
- */
- #include "examplelib.h"
-
- /*
- * Define the place where the library base is...
- */
- #define ExampleLibBase (getreg(REG_A6))
-
- /*
- * Prototypes for the library functions
- */
- #include "examplelib_proto.h"
- #include "examplelib_pragma.h"
-
- /*
- * We will define the prefix for our library vectors to be
- * _LIB so that the Cube call will call the real _LIBCube
- * vector in sted of calling the function directly.
- *
- * This is important as if the call to the function directly
- * was used, it would be impossible to "SetFunction" the function
- * and have ALL users of that function use the new one.
- *
- * Since C automatically adds the _ in front of labels,
- * we just need to have LIB defined...
- */
-
- long __saveds __asm LIBCube(register __d0 long num);
- long __saveds __asm LIBCount(void);
- void __saveds __asm LIBFunStuff(register __d0 long num,register __a0 char *name);
-
- /* Blink will plunk globals into the library base: */
- long Invocations = 314;
-
- /* This helps seed the random number generator */
- static ULONG RandomValue = (long)&RandomValue;
-
- /*
- * First external routine
- */
- long __saveds __asm LIBCube(register __d0 long num)
- {
- return(num*num*num);
- }
-
- /*
- * Second external routine that does not take arguments...
- */
- long __saveds __asm LIBCount(void)
- {
- long trivialtest;
-
- /*
- * Note that we call the LIBCube() function via Cube()
- * This makes this call go through the standard library
- * vectors.
- */
- trivialtest = Cube(5);
-
- /*
- * Since we will be modifying public data, we need
- * to protect it. That is what the MyDataSemaphore is.
- * Before using any public data that could be modified,
- * we grab the semaphore.
- *
- * Note that using the semaphore method is much better
- * than Forbid()/Permit() for overall system performance.
- * However, you can not use the Semaphore if you need to
- * call the function from within a Forbid()... (Since
- * ObtainSemaphore() could block...)
- */
- ObtainSemaphore(&MyDataSemaphore);
- Invocations++;
-
- /*
- * Note that we will copy the value into another "stack" variable
- * as after we release the semaphore the value may change.
- */
- trivialtest=Invocations;
- ReleaseSemaphore(&MyDataSemaphore);
-
- return(trivialtest);
- }
-
- /*
- * This routine is internal and uses the RandomValue global seed.
- */
- ULONG RandomNext(void)
- {
- ULONG NewRandom;
-
- ObtainSemaphore(&MyDataSemaphore);
- NewRandom=RandomValue;
- RandomValue=(((NewRandom<<13)^(NewRandom>>11))+NewRandom)>>1;
- ReleaseSemaphore(&MyDataSemaphore);
- return(NewRandom);
- }
-
- /*
- * This is an internal routine that just draws some stuff in the
- * window's RastPort.
- */
- void DrawStuff(struct Window *win)
- {
- short x;
- short y;
-
- x=win->Width-win->BorderLeft-win->BorderRight-1;
- y=win->Height-win->BorderTop-win->BorderBottom-1;
-
- SetDrMd(win->RPort,JAM1);
- SetAPen(win->RPort,RandomNext()%4);
- Move(win->RPort,(RandomNext() % x) + win->BorderLeft,
- (RandomNext() % y) + win->BorderTop);
- Draw(win->RPort,(RandomNext() % x) + win->BorderLeft,
- (RandomNext() % y) + win->BorderTop);
- }
-
- /*
- * Third external call that does some fun stuff...
- */
- void __saveds __asm LIBFunStuff(register __d0 long num,register __a0 char *name)
- {
- register short flag=TRUE;
- register struct Window *w;
- register struct IntuiMessage *msg;
- struct NewWindow nw;
-
- nw.LeftEdge=num;
- nw.TopEdge=num;
- nw.Width=486-num;
- nw.Height=143-num;
- nw.DetailPen=0;
- nw.BlockPen=1;
- nw.IDCMPFlags=CLOSEWINDOW|INTUITICKS;
- nw.Flags=WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|ACTIVATE;
- nw.Title=name;
- nw.FirstGadget=NULL;
- nw.MinWidth=nw.Width;
- nw.MinHeight=nw.Height;
- nw.MaxWidth=nw.Width;
- nw.MaxHeight=nw.Height;
- nw.Type=WBENCHSCREEN;
-
- if (w=OpenWindow(&nw))
- {
- while(flag)
- {
- DrawStuff(w);
- WaitPort(w->UserPort);
- if (msg=(struct IntuiMessage *)GetMsg(w->UserPort))
- {
- if (msg->Class==CLOSEWINDOW) flag=FALSE;
- ReplyMsg((struct Message *)msg);
- }
- }
- CloseWindow(w);
- }
- }
- -------------------------------------------------------------------------
- /*
- * 2) examplelib.h - example shared library to be made by blink 5.04
- *
- * These are the library globals...
- */
-
- #include <exec/types.h>
- #include <exec/semaphores.h>
-
- /*
- * This is the semaphore that we will use to protect the data
- */
- extern struct SignalSemaphore MyDataSemaphore;
-
- /*
- * This is a global data variable.
- */
- extern long Invocations;
-
-
-
- ------------------------------------------------------------------------------
- /*
- * 3) examplelib_custom.c
- *
- * Custom library initialization goes here...
- *
- * This contains the custom LibInit and LibExpunge routines for
- * the library we are making...
- */
-
- #include <exec/types.h>
- #include <exec/alerts.h>
- #include <proto/exec.h>
-
- #include <dos.h>
-
- /*
- * Include the prototypes for the custom init and expunge vectors...
- */
- #include "examplelib_custom.h"
-
- /*
- * Global data definition
- */
- #include "examplelib.h"
-
- /*
- * These are the libraries that we call from within our library.
- */
- struct ExecBase *SysBase = NULL;
- struct GfxBase *GfxBase = NULL;
- struct IntuitionBase *IntuitionBase = NULL;
-
- struct SignalSemaphore MyDataSemaphore;
-
- /*
- * This is the custom LibInit code.
- *
- * This is where the library specific initialization code should be.
- *
- * *** NOTE *** Note that it is best to use a little stack
- * as possible as you are being called from some
- * other process's context.
- *
- * Also note that the *FIRST* thing that must happen
- * in this routine is to set up SysBase as shown...
- */
- BOOL __saveds __asm CustomLibInit(register __a6 struct Library *libbase)
- {
- /* Get SysBase set up... this MUST happen *FIRST* */
- SysBase=(struct ExecBase *) (* ((ULONG *)4) );
-
- /* Initialize our semaphore */
- InitSemaphore(&MyDataSemaphore);
-
- /* Get the libraries we rely on */
- GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",33L);
- if (!GfxBase)
- {
- Alert(AG_OpenLib|AO_GraphicsLib,(APTR)libbase);
- /* !!! Bryce says nobody frees libbase ! */
- return ( FALSE );
- }
-
- IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",33L);
- if (!IntuitionBase)
- {
- Alert(AG_OpenLib|AO_Intuition,(APTR)libbase);
- /* !!! Bryce says nobody frees libbase! */
- /* !!! I'm not closing GfxBase, unless expunge is called! */
- return ( FALSE );
- }
- return ( TRUE );
- }
-
- /*
- * This is the custom LibExpunge code.
- *
- * This is where the library specific expunge code should be placed.
- *
- * *** NOTE *** This routine *MUST* *NEVER* *BREAK* *FORBID*
- * That is, it must not do *ANYTHING* that could
- * cause a Wait() to happen...
- *
- * Also note that it is best to use a little stack
- * as possible as you are being called from some
- * other process's context.
- */
- void __saveds __asm CustomLibExpunge(register __a6 struct Library *libbase)
- {
- /* Close the libraries it uses: */
- if (IntuitionBase)
- {
- CloseLibrary((struct Library *)IntuitionBase);
- IntuitionBase=NULL;
- }
- if (GfxBase)
- {
- CloseLibrary((struct Library *)GfxBase);
- GfxBase=NULL;
- }
- }
-
- ----------------------------------------------------------------------------
- /* 4) examplelib_custom.h
- *
- * The prototypes for the custom library init and expunge
- */
- BOOL __saveds __asm CustomLibInit(register __a6 struct Library *libbase);
- void __saveds __asm CustomLibExpunge(register __a6 struct Library *libbase);
-
- ----------------------------------------------------------------------------
-
- /* 5) example _lib.fd */
-
- ##base _ExampleLibBase
- ##bias 30
- Cube(num)(D0)
- Count()
- FunStuff(num,name)(D0/A0)
- ##end
-
- -------------------------------------------------------------------------------
- /*
- * 6) examplelib_proto.h - Prototypes for the example library
- */
- long Cube(long);
- long Count(void);
- void FunStuff(long,char *);
-
- -----------------------------------------------------------------------------
- /*
- * 7) examplelib_rev.h
- */
-
- #define VERSION 36
- #define REVISION 1
- #define DATE "27 Nov 1989"
- #define VERS "examplelib 36.1"
- #define VSTRING "examplelib 36.1 (27 Nov 1989)\n\r"
-
- -----------------------------------------------------------------------------
- /*
- * 8) examplelib_rev.i
- */
-
- VERSION EQU 36
- REVISION EQU 1
- DATE MACRO
- dc.b '27 Nov 1989'
- ENDM
- VERS MACRO
- dc.b 'examplelib 36.1'
- ENDM
- VSTRING MACRO
- dc.b 'examplelib 36.1 (27 Nov 1989)',13,10,0
- ENDM
-
-
- -----------------------------------------------------------------------------
- ***
- *
- * 9) libent.asm - Modified Lattice Library Resident (RomTag) Structure
- *
- ***
- include 'exec/types.i'
- include 'exec/resident.i'
- include 'exec/nodes.i'
- include 'exec/libraries.i'
- ***
- *
- * The following include is used to store the library version and name
- * as follows:
- *
- * VERSION EQU 36
- * REVISION EQU 1
- * DATE MACRO
- * dc.b '27 Nov 1989'
- * ENDM
- * VERS MACRO
- * dc.b 'examplelib 36.1'
- * ENDM
- * VSTRING MACRO
- * dc.b 'examplelib 36.1 (27 Nov 1989)',13,10,0
- * ENDM
- *
- ***
- include 'examplelib_rev.i'
- ***
- *
- * Library init priority. For user (NON-ROM) libraries, should be 0
- *
- ***
- PRI equ 0
- ***
- *
- * Define some the external references...
- *
- ***
- xref __LibName
- xref RESLEN
- xref _BSSBAS ; linker defined base of BSS
- xref _BSSLEN ; linker defined length of BSS
- xref _LibFuncTab
- xref __LibInitTab
- xref endtag
- xref _LibInit
- xdef __LibRomTag
- xdef __VerString
- ***
- *
- * This is the first hunk and is where the RomTag is needed...
- *
- ***
- SECTION text,CODE ; romtag must be in first hunk
- ***
- *
- * We need to make sure that if some user tries to execute this
- * file as an executable that we return an error...
- *
- ***
- moveq #20,d0
- rts
- ***
- *
- * Place the version string into the tag. This makes the
- * version displayable. It also makes it possible to "TYPE"
- * the library file to find out the version...
- *
- ***
- __VerString: VSTRING
- ***
- *
- * The RomTag that is needed for a library
- *
- ***
- cnop 0,2 ; We need to word-align the RomTag
- __LibRomTag:
- dc.w RTC_MATCHWORD
- dc.l __LibRomTag
- dc.l endtag
- dc.b RTF_AUTOINIT
- dc.b VERSION
- dc.b NT_LIBRARY
- dc.b PRI
- dc.l __LibName
- dc.l __VerString
- dc.l __LibInitTab
- ***
- *
- * Start of the merged data area that the linker puts
- * into the library structure for the global data.
- *
- ***
- section __MERGED,data
- xdef __Libmergeddata
- __Libmergeddata dc.l 0
- end
-
-
- ---------------------------------------------------------------------------
- *
- * 10) endtag.a - For RomTag EndSkip
- *
- section text,data ; so it is dead-last (data hunk)
-
- XDEF endtag
- endtag:
-
- END
-
- ---------------------------------------------------------------------------
- /*
- * 11) libinit.c
- *
- * This is the standard library init...
- *
- * It calls the custom init routines in examplelib_custom.c
- * The routines in this file should not be changed.
- *
- * Portions of this code were generated from Lattice examples...
- */
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/resident.h>
- #include <exec/libraries.h>
- #include <libraries/dos.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <string.h>
-
- /*
- * This includes the revision information
- */
- #include "examplelib_rev.h"
-
- /*
- * Include the custom init and expunge headers...
- *
- * The MUST be of the type:
- * BOOL __asm __saveds CustomLibInit(register __a6 struct Library *libbase);
- * void __asm __saveds CustomLibExpunge(register __a6 struct Library *libbase);
- *
- */
- #include "examplelib_custom.h"
-
- struct MyLibrary
- {
- struct Library ml_Lib;
- ULONG ml_SegList;
- ULONG ml_Flags;
- APTR ml_ExecBase; /* pointer to exec base */
- LONG ml_Data; /* Global data */
- };
-
- typedef LONG (*PFL)(); /* pointer to function returning 32-bit int */
-
- /* library initialization table, used for AUTOINIT libraries */
- struct InitTable
- {
- ULONG *it_DataSize; /* library data space size */
- PFL *it_FuncTable; /* table of entry points */
- APTR it_DataInit; /* table of data initializers */
- PFL it_InitFunc; /* initialization function to run */
- };
-
- /* my function table (Generated by Blink) */
- extern PFL _LibFuncTab[];
-
- extern char __far RESLEN;
- extern long __far NEWDATAL; /* Generated by BLINK */
-
- #define DATAWORDS ((long)&NEWDATAL)
-
- /* We need to define this for the following table */
- ULONG __asm _LibInit(register __a0 APTR seglist,register __d0 struct MyLibrary *libbase);
-
- struct InitTable __far _LibInitTab =
- {
- (long *)(&RESLEN+sizeof(struct MyLibrary)),
- _LibFuncTab,
- NULL, /* will initialize my own data */
- _LibInit,
- };
-
- /* Need this to determine start of MERGED DATA */
- extern long far _Libmergeddata;
-
- /* Supplied by BLink */
- extern char __far _LibName[];
-
- /* Supplied as part of our libent.a */
- extern char __far _VerString[];
-
- /*
- * The following #define is to give the EXEC call #pragmas
- * (which were changed to "libcall SysBase" to use the
- * absolute location known also as AbsExecBase. This is
- * needed during the base level expunge call...
- */
- #define SysBase (*((ULONG *)4))
-
- /*
- * This function is called when the library is first loaded.
- * It does the library structure initialization and calls
- * the custom library initialization routine which should
- * setup any custom library stuff and open any other libraries
- * that will be needed.
- *
- * Note that this routine can not change as the setup must
- * happen in this order.
- */
- ULONG __asm _LibInit(register __a0 APTR seglist,register __d0 struct MyLibrary *libbase)
- {
- long *sdata, *reloc;
- char *ddata;
- long nrelocs;
-
- libbase->ml_SegList = (ULONG) seglist;
-
- /* init. library structure (since I don't do automatic data init.) */
- libbase->ml_Lib.lib_Node.ln_Type = NT_LIBRARY;
- libbase->ml_Lib.lib_Node.ln_Name = _LibName;
- libbase->ml_Lib.lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
- libbase->ml_Lib.lib_Version = VERSION;
- libbase->ml_Lib.lib_Revision = REVISION;
- libbase->ml_Lib.lib_IdString = (APTR) _VerString;
-
- /* The +4 is a wasted long word, where _Libmergeddata is. */
- ddata = (char *)&libbase->ml_Data+4;
- sdata = (long *)&_Libmergeddata;
- memcpy(ddata, (char *)sdata, DATAWORDS*4);
-
- sdata = sdata + DATAWORDS;
- nrelocs = *sdata++;
- while (nrelocs > 0)
- {
- reloc = (long *)((long)ddata + *sdata++);
- *reloc += (long)ddata;
- nrelocs--;
- }
-
- if (CustomLibInit((struct Library *)libbase)) return((ULONG)libbase);
- else return(NULL);
- }
-
- /*
- * This is the entry point that is called when the system
- * wishes that the library free itself. The library should
- * only free itself if there are no outstanding open libraries.
- * This routine calls the custom expunge routine where any
- * custom resources that need to be freed are.
- *
- * *** NOTE *** This routine *MUST* *NEVER* *BREAK* *FORBID*
- * That is, it must not do *ANYTHING* that could
- * cause a Wait() to happen...
- *
- * Also note that it is best to use a little stack
- * as possible as you are being called from some
- * other process's context.
- */
- ULONG __saveds __asm _LibExpunge( register __a6 struct MyLibrary *libbase )
- {
- ULONG seglist = 0;
- LONG libsize;
-
- libbase->ml_Lib.lib_Flags |= LIBF_DELEXP;
- if ( libbase->ml_Lib.lib_OpenCnt == 0 )
- {
- CustomLibExpunge((struct Library *)libbase);
-
- /* really expunge: remove libbase and freemem */
-
- seglist = libbase->ml_SegList;
- Remove( (struct Node *) libbase);
-
- libsize = libbase->ml_Lib.lib_NegSize + libbase->ml_Lib.lib_PosSize;
- FreeMem( (char *) libbase - libbase->ml_Lib.lib_NegSize,(LONG) libsize );
- }
-
- /* return NULL or real seglist */
- return ( (ULONG) seglist );
- }
-
- /*
- * This is the entry point that is called when the library is
- * opened by an application. It mainly changes the OpenCount
- * and the delayed expunge flags...
- */
- LONG __asm _LibOpen(register __a6 struct MyLibrary *libbase)
- {
- /* mark us as having another customer */
- libbase->ml_Lib.lib_OpenCnt++;
-
- /* clear delayed expunges (standard procedure) */
- libbase->ml_Lib.lib_Flags &= ~LIBF_DELEXP;
-
- return((LONG)libbase);
- }
-
- /*
- * This is the entry point that is called when the library is
- * closed by an application. The main use here is to change the
- * open count and to check for delayed expunge calls...
- */
- ULONG __asm _LibClose( register __a6 struct MyLibrary *libbase )
- {
- ULONG retval = 0;
-
- if (( --libbase->ml_Lib.lib_OpenCnt == 0 ) &&
- ( libbase->ml_Lib.lib_Flags & LIBF_DELEXP ))
- {
- /*
- * no more people have me open,
- * and I have a delayed expunge pending
- */
- retval = _LibExpunge( libbase ); /* return segment list */
- }
-
- return (retval);
- }
-
-
- ---------------------------------------------------------------------------
- /*
- * 12) libtest.c
- */
-
- #include <proto/exec.h>
-
- #include "examplelib_proto.h"
- #include "examplelib_pragma.h"
-
- struct Library *ExampleLibBase;
-
- main()
- {
- if (ExampleLibBase = OpenLibrary("examplelib.library", 0L))
- {
- FunStuff(8,"Test with num==8");
- printf("ExampleLibBase at $%lx\n", ExampleLibBase);
- printf("Cube 5 = %ld\n", Cube(5));
- printf("Invocations: %ld\n", Count());
- FunStuff(12,"Test with num==12");
- CloseLibrary(ExampleLibBase);
- }
- else printf("examplelib.library did not open...\n");
- }
-
- ------------------------------------------------------------------------
- #
- # 13) lmkfile
- #
- # These are the files for the library.
- # You MUST have a xxx_custom.o for the init/expunge part of the library
- #
- OFILES=examplelib_custom.o examplelib.o
-
- #
- # These are files needed for the library initialization
- # They should not need to be changed other than the headers
- #
- LIBOFILES=libent.o libinit.o
-
- #
- # These are the flags needed to compile library routines...
- #
- CFLAGS=-ml -cfist -v -d2
-
- #
- # The flags needed to assemble the RomTag and EndTag...
- #
- AFLAGS=-iINCLUDE:
-
- #
- # Default rules...
- #
- .c.o:
- lc $(CFLAGS) $*
-
- .a.o:
- asm $(AFLAGS) $*
-
- #
- # The whole world...
- #
- all: examplelib_pragma.h examplelib.library libtest
-
- #
- # This is a little LMK trick for blink...
- #
- # Note that the LIBID is a place to put copyright notices or other
- # information that you may wish to have as part of the library...
- #
- examplelib.library: $(OFILES) $(LIBOFILES) examplelib_lib.fd endtag.o lmkfile
- blink <with <
- LIBID "Example Library of no real use..."
- LIBPREFIX _LIB
- LIBFD examplelib_lib.fd
- TO examplelib.library
- FROM $(LIBOFILES) $(OFILES)
- LIB lib:lc.lib endtag.o
- SMALLCODE SMALLDATA NODEBUG
- <
-
- examplelib_pragma.h: examplelib_lib.fd
- fd2pragma examplelib_lib.fd examplelib_pragma.h
-
- libtest: libtest.c examplelib_pragma.h
- lc -L -d2 libtest.c
-
- libent.o: libent.a examplelib_rev.i
-
- libinit.o: libinit.c examplelib_rev.h
-
- endtag.o: endtag.a
-
-